using System;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Text;
using LoD.Contracts;
using LoD.WPClientLibrary.Helper;
using LoD.WPClientLibrary.Interfaces;
using LoD.WPClientLibrary.MapEngine;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input.Touch;
using TileSet = LoD.Contracts.TileSet;


namespace LoD.WPClient.Modules {
    public class MapEngine : IGameModule {
        private const int MapBaseOffsetX = -32;
        private const int MapBaseOffsetY = -64;
        private const float MapHeightRowDepthMod = 0.00001f;
        private const int VisibleTilesX = 20;
        private const int VisibleTilesY = 35;
        private readonly GameClass _game;
        private ViewPort _camera;
        private SpriteFont _debugFont;
        private TileMap _map;
        private Random _random;
        private WPClientLibrary.MapEngine.TileSet _tileSet;

        public MapEngine(GameClass game) {
            this._game = game;
            this._random = new Random();
        }

        #region IGameModule Members

        public void Reset() { }

        public void LoadContent(ContentManager content) {
            this._debugFont = content.Load<SpriteFont>("Fonts/Debug");
            this._tileSet = new WPClientLibrary.MapEngine.TileSet(content.Load<Texture2D>(string.Format(@"Grounds/{0}", TileSet.test_tileset_1)), 64, 64, 64, 16, 32, 32,
                                        new Vector2(19, 39));
            this._map = new TileMap(content.Load<Texture2D>(@"Helper/MouseMap"),
                                    content.Load<Texture2D>(@"Helper/SlopeMaps"), this._tileSet, 50, 50);
            this._camera = new ViewPort(this._game.Graphics.PreferredBackBufferWidth,
                                        this._game.Graphics.PreferredBackBufferHeight,
                                        (this._map.MapWidth - 2) * this._tileSet.TileStepX,
                                        (this._map.MapHeight - 2) * this._tileSet.TileStepY,
                                        new Vector2(MapBaseOffsetX, MapBaseOffsetY));

            var client = new WebClient();
            client.OpenReadCompleted += (sender, e) => this._map.Import(e.Result);
            client.OpenReadAsync(new Uri("http://static.gordon-breuer.de/LoD/testmap.txt")); 
        }

        public void Update(TouchLocation touch, GameTime gameTime) { }

        public void Draw(GameTime gameTime) {
            this._game.Graphics.GraphicsDevice.Clear(Color.Black);

            var firstSquare = new Vector2(this._camera.Location.X / this._tileSet.TileStepX,
                                          this._camera.Location.Y / this._tileSet.TileStepY);
            var firstX = (int)firstSquare.X;
            var firstY = (int)firstSquare.Y;

            var squareOffset = new Vector2(this._camera.Location.X % this._tileSet.TileStepX,
                                           this._camera.Location.Y % this._tileSet.TileStepY);
            var offsetX = (int)squareOffset.X;
            var offsetY = (int)squareOffset.Y;

            float maxdepth = ((this._map.MapWidth + 1) * ((this._map.MapHeight + 1) * this._tileSet.TileWidth)) / 10;
            float depthOffset;

            for (int y = 0; y < VisibleTilesY; y++) {
                int rowOffset = 0;
                if ((firstY + y) % 2 == 1) rowOffset = this._tileSet.OddRowXOffset;

                for (int x = 0; x < VisibleTilesX; x++) {
                    int mapx = (firstX + x);
                    int mapy = (firstY + y);
                    depthOffset = 0.7f - ((mapx + (mapy * this._tileSet.TileWidth)) / maxdepth);

                    if ((mapx >= this._map.MapWidth) || (mapy >= this._map.MapHeight)) continue;

                    foreach (int tileID in this._map.Rows[mapy].Columns[mapx].BaseTiles) {
                        this._game.SpriteBatch.Draw(
                                                    this._tileSet.TileSetTexture,
                                                    this._camera.WorldToScreen(
                                                                               new Vector2(
                                                                                   (mapx * this._tileSet.TileStepX)
                                                                                   + rowOffset,
                                                                                   mapy * this._tileSet.TileStepY)),
                                                    this._tileSet.GetSourceRectangle(tileID),
                                                    Color.White,
                                                    0.0f,
                                                    Vector2.Zero,
                                                    1.0f,
                                                    SpriteEffects.None,
                                                    1.0f);
                    }
                    int heightRow = 0;

                    foreach (int tileID in this._map.Rows[mapy].Columns[mapx].StackTiles) {
                        this._game.SpriteBatch.Draw(
                                                    this._tileSet.TileSetTexture,
                                                    this._camera.WorldToScreen(
                                                                               new Vector2(
                                                                                   (mapx * this._tileSet.TileStepX)
                                                                                   + rowOffset,
                                                                                   mapy * this._tileSet.TileStepY
                                                                                   -
                                                                                   (heightRow
                                                                                    * this._tileSet.HeightTileOffset))),
                                                    this._tileSet.GetSourceRectangle(tileID),
                                                    Color.White,
                                                    0.0f,
                                                    Vector2.Zero,
                                                    1.0f,
                                                    SpriteEffects.None,
                                                    depthOffset - (heightRow * MapHeightRowDepthMod));
                        heightRow++;
                    }

                    foreach (int tileID in this._map.Rows[y + firstY].Columns[x + firstX].Tiles) {
                        this._game.SpriteBatch.Draw(
                                                    this._tileSet.TileSetTexture,
                                                    this._camera.WorldToScreen(
                                                                               new Vector2(
                                                                                   (mapx * this._tileSet.TileStepX)
                                                                                   + rowOffset,
                                                                                   mapy * this._tileSet.TileStepY)),
                                                    this._tileSet.GetSourceRectangle(tileID),
                                                    Color.White,
                                                    0.0f,
                                                    Vector2.Zero,
                                                    1.0f,
                                                    SpriteEffects.None,
                                                    depthOffset - (heightRow * MapHeightRowDepthMod));
                    }

                    //this._game.SpriteBatch.DrawString(this._debugFont,
                    //                                  (x + firstX).ToString() + ", " + (y + firstY).ToString(),
                    //                                  new Vector2(
                    //                                      (x * this._tileSet.TileStepX) - offsetX + rowOffset
                    //                                      + MapBaseOffsetX + 24,
                    //                                      (y * this._tileSet.TileStepY) - offsetY + MapBaseOffsetY + 48),
                    //                                  Color.White,
                    //                                  0f, Vector2.Zero,
                    //                                  1.0f, SpriteEffects.None, 0.0f);
                }
            }
        }

        #endregion
    }
}